package com.youzhi.backend.service.impl;

import com.youzhi.backend.config.ShiroConfig;
import com.youzhi.backend.dto.MessageType;
import com.youzhi.backend.exception.EcpEnum;
import com.youzhi.backend.exception.YouZhiException;
import com.youzhi.backend.service.IMessageService;
import com.youzhi.backend.service.IUserSessionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.subject.support.WebDelegatingSubject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.ServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class UserSessionServiceImpl implements IUserSessionService {


    public static String session_prefix = "session:";

    public static String user_state_prefix = "user:";

    public static String JSESSIONID = "JSESSIONID";

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    @Autowired
    private IMessageService service;


    @Override
    public void remove(String userName) {
        Object sessionId = get(userName, IUserSessionService.attr_sessionId);
        Object webSocketId = get(userName, IUserSessionService.attr_webSocketId);
        if (sessionId != null) {
            //删除掉老的session key
            redisTemplate.delete(getSessionKey(sessionId.toString()));

            //删除掉老的用户当前登陆数据缓存
            redisTemplate.delete(getHashKey(userName));

            //告知被挤的消息给前端
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("webSocketId", webSocketId);
            service.sendMessage(MessageType.kick_off_line, dataMap);

        }
    }


    @Override
    public void login(String userName, String password) {
        try {

            password = new Sha256Hash(password).toHex();
            UsernamePasswordToken token = new UsernamePasswordToken(userName, password, false);

            //登陆
            SecurityUtils.getSubject().login(token);

        } catch (AuthenticationException e) {
            throw YouZhiException.newException(EcpEnum.login_fail, e);

        }

    }


    @Override
    public void logout() {

        String currentUser = getCurrentUser();

        //退出登陆
        SecurityUtils.getSubject().logout();

        Object sessionId = get(currentUser, IUserSessionService.attr_sessionId);
        //删除掉用户session key
        redisTemplate.delete(getSessionKey(sessionId.toString()));
        //删除掉用户当前登陆数据缓存
        redisTemplate.delete(getHashKey(currentUser));
    }


    private Object get(String userName, String key) {
        HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
        return hashOperations.get(getHashKey(userName), key);
    }

    private String getSessionKey(Serializable sessionId) {
        return session_prefix + sessionId;
    }

    private String getHashKey(String userName) {
        return user_state_prefix + userName;
    }


    /**
     * 获取当前登陆用户属性
     *
     * @param attrName
     * @return
     */
    @Override
    public Object getCurrentUserAttr(String attrName) {
        return get(getCurrentUser(), attrName);
    }


    @Override
    public void setCurrentUserAttr(String key, Object value) {
        String currentUser = getCurrentUser();
        put(currentUser, key, value);
    }

    @Override
    public void setCurrentUserAttr(Map<String, Object> map) {
        String currentUser = getCurrentUser();
        HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
        hashOperations.putAll(getHashKey(currentUser), map);
        redisTemplate.expire(getHashKey(currentUser), ShiroConfig.session_milliseconds_time_out, TimeUnit.MILLISECONDS);
    }


    /**
     * 获取当前登陆用户名
     *
     * @return
     */
    @Override
    public String getCurrentUser() {
        Subject subject = SecurityUtils.getSubject();
        Object principal = subject.getPrincipal();
        return principal != null ? principal.toString() : null;
    }

    private String getJSESSIONID(Subject principal) {
        ServletRequest servletRequest = ((WebDelegatingSubject) principal).getServletRequest();
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (int i = 0; i < cookies.length; i++) {
                Cookie cookie = cookies[i];
                if (JSESSIONID.equals(cookie.getName())) {
                    return cookie.getValue();
                }
            }
        }
        return null;
    }


    /**
     * 获取当前登陆用户sessionId
     *
     * @return
     */
    @Override
    public Serializable getCurrentSessionId() {
        return SecurityUtils.getSubject().getSession().getId();
    }

    @Override
    public String getUserWebsocketId(String userName) {
        Object o = get(userName, attr_webSocketId);
        if (o != null) {
            return o.toString();
        }
        return null;
    }

    @Override
    public boolean isLogin(String userName) {
        return redisTemplate.hasKey(getHashKey(userName));
    }

    private void put(String userName, String key, Object value) {
        HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
        hashOperations.put(getHashKey(userName), key, value);
        redisTemplate.expire(getHashKey(userName), ShiroConfig.session_milliseconds_time_out, TimeUnit.MILLISECONDS);
    }


}
